﻿using Dapper;
using Dapper.Contrib.Extensions;
using Dapper.SimpleDao.Entity;
using Dapper.SimpleDao.Factory;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MySql.Data.MySqlClient;
using System;
using System.Data;

namespace Dapper.SimpleDao.Infrastructure
{
    public class Repository<T> : IRepository<T> where T : BaseEntitiy
    {
        public IDbContext Context { get; private set; }
        public Repository(IDbContext context)
        {
            Context = context;
        }

        #region 同步代码
        /// <summary>
        /// 获取单个实体
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns></returns>
        public T Get(string id)
        {
            using (var connection = Context.Connection)
            {
                return connection.Get<T>(id);
            }
        }
        /// <summary>
        /// 插入一个实体
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int Insert(T obj, IDbTransaction tran = null)
        {
            var map = MySqlDbBuilder.AddSqlMap(obj);
            return Execute(map.Sql, map.Param, tran);
        }
        /// <summary>
        /// 更新一个实体
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int Update(T obj, IDbTransaction tran = null)
        {
            var map = MySqlDbBuilder.UpdateSqlMap(obj);
            return Execute(map.Sql, map.Param, tran);
        }
        /// <summary>
        /// 根据条件查询实体列表
        /// </summary>
        /// <typeparam name="TDbModel">返回的数据实体</typeparam>
        /// <param name="where">条件</param>
        /// <param name="page">页数</param>
        /// <param name="size">条数</param>
        /// <param name="total">总数</param>
        /// <returns></returns>
        public IEnumerable<TDbModel> FindAll<TDbModel>(IDictionary<string, object> where, int page, int size, out int total)
            where TDbModel : class
        {
            using (var connection = Context.Connection)
            {
                var count = MySqlDbBuilder.SelectCountSqlMap<T, TDbModel>(where);
                var query = MySqlDbBuilder.SelectSqlMap<T, TDbModel>(where, page, size);
                if (where != null && where.Count() > 0)
                {
                    using (var multi = connection.QueryMultiple(count.Sql + query.Sql, where))
                    {
                        var t = multi.Read().SingleOrDefault();
                        total = t == null ? 0 : (int)t.total;
                        return multi.Read<TDbModel>();
                    }
                }
                using (var multi = connection.QueryMultiple(count.Sql + query.Sql))
                {
                    var t = multi.Read().SingleOrDefault();
                    total = t == null ? 0 : (int)t.total;
                    return multi.Read<TDbModel>();
                }
            }

        }
        /// <summary>
        /// 根据条件查询实体列表
        /// </summary>
        /// <typeparam name="TDbModel">返回的数据实体</typeparam>
        /// <param name="where">条件</param>
        /// <param name="page">页数</param>
        /// <param name="size">条数</param>
        /// <param name="total">总数</param>
        /// <param name="sort">排序</param>
        /// <param name="op">操作</param>
        /// <returns></returns>
        public IEnumerable<TDbModel> FindAll<TDbModel>(IEnumerable<FieldPredicate<T>> where, int page, int size, out int total, IEnumerable<PropertySort<T>> sort = null, GroupOperator op = GroupOperator.And)
            where TDbModel : class
        {
            using (var connection = Context.Connection)
            {
                var count = MySqlDbBuilder.SelectCountSqlMap<T, TDbModel>(where, sort);
                var query = MySqlDbBuilder.SelectSqlMap<T, TDbModel>(where, page, size, sort, op);
                if (query.Param != null)
                {
                    using (var multi = connection.QueryMultiple(count.Sql + query.Sql, query.Param))
                    {
                        var t = multi.Read().SingleOrDefault();
                        total = t == null ? 0 : (int)t.total;
                        return multi.Read<TDbModel>();
                    }
                }
                using (var multi = connection.QueryMultiple(count.Sql + query.Sql))
                {
                    var t = multi.Read().SingleOrDefault();
                    total = t == null ? 0 : (int)t.total;
                    return multi.Read<TDbModel>();
                }
            }
        }
        #endregion

        #region 异步代码
        public Task<T> GetAsync(string id)
        {
            using (var connection = Context.Connection)
            {
                return connection.GetAsync<T>(id);
            }
        }
        #endregion

        public bool Commit(IEnumerable<FuncParamater<T>> funcs)
        {
            using (var connection = Context.Connection)
            {
                using (var tran = connection.BeginTransaction())
                {
                    try
                    {
                        foreach (var fp in funcs)
                        {
                            fp.func(fp.obj, tran);
                        }
                        tran.Commit();
                        return true;
                    }
                    catch (MySqlException e)
                    {
                        tran.Rollback();
                        throw e;
                    }
                }
            }
        }

        private int Execute(string sql, object paras, IDbTransaction tran)
        {
            if (tran == null)
            {
                return 0;
            }
            return Context.Connection.Execute(sql, paras, tran);
        }
    }
}
